/** @file    WoshTableModel.cpp
 *  @author  Alessandro Polo
 *  @version $Id: WoshTableModel.cpp 2891 2010-08-12 01:58:59Z alex $
 *  @brief
 * File containing methods for the wosh::gui::WoshTableModel class.
 * The header for this class can be found in WoshTableModel.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include "WoshTableModel.h"

 #include <framework/gui/components/WidgetUpdateBar.h>
 #include <QtGui/QLabel>
 #include <QtGui/QSpinBox>


using namespace std;
namespace wosh {
 namespace gui {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

QWidget* GenericItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
	if ( index.data().type() == QVariant::Int ) {
		QSpinBox *editor = new QSpinBox(parent);
		return editor;
	 }
	else if ( index.data().type() == QVariant::Double ) {
		QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
		return editor;
	 }
	else if ( index.data().type() == QVariant::DateTime ) {
		QDateTimeEdit *editor = new QDateTimeEdit(parent);
		return editor;
	 }
/*
	else if ( index.data().canConvert<wosh::List>() ) {
		QListWidget *editor = new QListWidget(parent);
		return editor;
	 }
*/
	return QItemDelegate::createEditor(parent, option, index);
 }

void GenericItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {
	if ( index.data().type() == QVariant::Int ) {
		QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
		int value = index.model()->data(index, Qt::EditRole).toInt();
		spinBox->setValue(value);
	 }
	else if ( index.data().type() == QVariant::Double ) {
		QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
		double value = index.model()->data(index, Qt::EditRole).toDouble();
		spinBox->setValue(value);
	 }
	else if ( index.data().type() == QVariant::DateTime ) {
		QDateTimeEdit *dateEditBox = static_cast<QDateTimeEdit*>(editor);
		QDateTime value = index.model()->data(index, Qt::EditRole).toDateTime();
		dateEditBox->setDateTime(value);
	 }
/*			else if ( index.data().canConvert<wosh::List>() ) {
		QListWidget *editor = static_cast<QListWidget*>(editor);
		wosh::List c;
		c = index.data().value<wosh::List>();
		editor->addItem("asd");
	 }
*/
	else
		QItemDelegate::setEditorData(editor, index);
 }

void GenericItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
	if ( index.data().type() == QVariant::Int ) {
		QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
		spinBox->interpretText();
		int value = spinBox->value();
		model->setData(index, value, Qt::EditRole);
	 }
	else if ( index.data().type() == QVariant::Double ) {
		QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
		spinBox->interpretText();
		double value = spinBox->value();
		model->setData(index, value, Qt::EditRole);
	 }
	else if ( index.data().type() == QVariant::DateTime ) {
		QDateTimeEdit *dateEditBox = static_cast<QDateTimeEdit*>(editor);
		dateEditBox->interpretText();
		QDateTime value = dateEditBox->dateTime();
		model->setData(index, value, Qt::EditRole);
	 }
	else
		QItemDelegate::setModelData(editor, model, index);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WoshTableModel::WoshTableModel( const wosh::Table* table, QObject *parent )
	: QAbstractTableModel(parent) {
	this->dataTable = NULL;
	this->editingUserSecurity = NULL;
	this->forceKeyCol = -2;
	this->permissionCol = -2;
	this->permissionType = Permission::Write;
	loadTable( table );
 }

WoshTableModel::~WoshTableModel() {
	if ( this->dataTable != NULL )
		delete this->dataTable; this->dataTable = NULL;
	if ( this->editingUserSecurity != NULL )
		delete this->editingUserSecurity; this->editingUserSecurity = NULL;
 }

void WoshTableModel::loadTable( const wosh::Table* table ) {
	if ( this->dataTable != NULL )
		delete this->dataTable; this->dataTable = NULL;
	if ( table != NULL ) {
		this->dataTable = table->clone();
	 }
	analyzeTable();
	reset();
 }

void WoshTableModel::acquireTable( wosh::Table* table) {
	if ( this->dataTable != NULL )
		delete this->dataTable; this->dataTable = NULL;
	this->dataTable = table;
	analyzeTable();
	reset();
 }

void WoshTableModel::analyzeTable() {
	if ( this->dataTable == NULL )
		return;
	if ( this->permissionCol == -2 ) {
		for(unsigned int col=0; col<this->dataTable->getCols(); col++) {
			if ( this->dataTable->getClassNameOfCol(col) != "wosh::Permission" )
				continue;
			this->permissionCol = col;
			break;
		 }
	 }
	if ( this->forceKeyCol == -2 ) {
		if ( this->dataTable->hasHeaderHorizontal() ) {
			for(unsigned int col=0; col<this->dataTable->getCols(); col++) {
				const ISerializable* object = this->dataTable->getHeaderHorizontal(col);
				if ( object == NULL || !object->isKindOf<Variant>() )
					continue;
				const wosh::Variant* dataObject = dynamic_cast<const wosh::Variant*>(object);
				if ( dataObject== NULL || *dataObject != "Name" )
					continue;
				this->forceKeyCol = col;
				break;
			 }
		 }
	 }

 }

void WoshTableModel::updateTable( const wosh::Table* table ) {
	if ( this->dataTable == NULL ) {
		loadTable(table);
		return;
	 }
	if ( table == NULL ) {
		delete this->dataTable; this->dataTable = NULL;
		reset();
		return;
	 }
	if ( table->getCols() != this->dataTable->getCols() ) {
		// different colums count => refresh ALL
		loadTable(table);
		return;
	 }

	if ( forceKeyCol > -1 && forceKeyCol < (int)this->dataTable->getCols() ) {
		// optimization when updating a single row:
		unsigned int rowsNew = this->dataTable->getRows();
		unsigned int rows = this->dataTable->getRows();
		unsigned int cols = this->dataTable->getCols();
		for(unsigned int rowNew=0; rowNew<rowsNew; rowNew++) {
			const ISerializable* objectKey = table->get(0, forceKeyCol);
			if ( objectKey == NULL ) continue;
			// iterate each cached item
			for(unsigned int row=0; row<rows; row++) {
				ISerializable* objectOld = this->dataTable->get(row, forceKeyCol);
				if ( objectOld == NULL ) continue;
				if ( objectKey->compare(objectOld) == 0 ) {
					// update row (but key)
					for(unsigned int col=0; col<cols; col++) {
						if ( (int)col == forceKeyCol ) continue;
						const ISerializable* objectCurr = table->get(rowNew, col);
						if ( objectCurr != NULL )
							this->dataTable->set(objectCurr->clone(), row, col, true);
						else
							this->dataTable->set(NULL, row, col, true);
					 }
				 }
			 }
		 }
		reset();
		return;
	 }
	///@todo may be optimized more!!
	loadTable(table);
	return;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

QVariant WoshTableModel::data(const QModelIndex &index, int role) const {
	if ( this->dataTable == NULL || !index.isValid() ) return QVariant();
	if ( role == Qt::DisplayRole || role == Qt::EditRole ) {
		const ISerializable* object = this->dataTable->get(index.row(), index.column() );
		if ( object == NULL )
			return QVariant();
		return GuiUtilities::convertSerializable2QVariant(object);
	 }
	else if ( role == Qt::BackgroundColorRole ) {
		if ( dataTable->getClassNameOfCol(index.column()) != "wosh::Permission" )
			return QVariant();
		const ISerializable* object = this->dataTable->get(index.row(), index.column() );
		if ( object == NULL || !object->isKindOf<Permission>() )
			return QVariant();
		const wosh::Permission* dataPerm = dynamic_cast<const wosh::Permission*>(object);
		bool allowInteract = evalAuthorization( dataPerm, this->permissionType );
		if ( allowInteract )
			return QColor(229,255,229);
		else
			return QColor(255,198,179);
	 }
	else if ( role == Qt::ToolTipRole ) {
		const ISerializable* object = this->dataTable->get(index.row(), index.column() );
		if ( object == NULL )
			return QVariant("NULL Object");
		if ( object->isKindOf<Variant>() ){
			const wosh::Variant* dataObject = dynamic_cast<const wosh::Variant*>(object);
			return QString("wosh::Variant [%1]").arg(dataObject->getTypeAsString());
		 }
		return QVariant(object->getClassName());
	 }
	return QVariant();
 }

QVariant WoshTableModel::headerData(int section, Qt::Orientation orientation, int role ) const {
	if ( this->dataTable == NULL ) return QVariant();
	if (role != Qt::DisplayRole) return QVariant();
	 if (orientation == Qt::Horizontal ) {
		 if ( this->dataTable->hasHeaderHorizontal() ) {
			ISerializable* object = this->dataTable->getHeaderHorizontal(section);
			if ( object == NULL )
				return QString("Col%1").arg(section);
			if ( object->isKindOf<Variant>() ) {
				wosh::Variant* dataObject = dynamic_cast<wosh::Variant*>(object);
				return QVariant(dataObject->toString().c_str());
			 }
			else
				return QVariant(object->toString().c_str());
		 }
		//return QString("Col%1").arg(section);
	 }
	else if (orientation == Qt::Vertical ) {
		if ( this->dataTable->hasHeaderVertical() ) {
			ISerializable* object = this->dataTable->getHeaderVertical(section);
			if ( object == NULL )
				return QString("Row%1").arg(section);
			if ( object->isKindOf<Variant>() ) {
				wosh::Variant* dataObject = dynamic_cast<wosh::Variant*>(object);
				return QVariant(dataObject->toString().c_str());
			 }
			else
				return QVariant(object->toString().c_str());
		 }
		//return QString("Row%1").arg(section);
	 }
	return QVariant();
 }

 Qt::ItemFlags WoshTableModel::flags(const QModelIndex &index) const {
	if ( this->dataTable == NULL || !index.isValid() )
		 return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled;
	if ( this->permissionCol == -2 )
		 return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled;
	if ( this->permissionCol == -3 )
		 return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;

	if ( this->forceKeyCol == index.column() )
		 return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled;

	if ( this->permissionCol == -1 ) {
		bool allowWrite = evalAuthorization( &this->tablePermission, Permission::Write );
		if ( !allowWrite )
			return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled;
	 }

	ISerializable* object = this->dataTable->get(index.row(), this->permissionCol );
	if ( object == NULL )
		 return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled;
	if ( !object->isKindOf<Permission>() )
		 return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled;
	wosh::Permission* dataPerm = dynamic_cast<wosh::Permission*>(object);

	bool allowWrite = evalAuthorization( dataPerm, Permission::Write );
	if ( !allowWrite )
		return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled;

	return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
  }

bool WoshTableModel::setData(const QModelIndex &index, const QVariant &value, int role) {
	if ( this->dataTable == NULL ) return false;
	if ( !index.isValid() || role != Qt::EditRole) return false;

	ISerializable* object = this->dataTable->get(index.row(), index.column() );
	if ( object == NULL )
		return false;

	if ( object->isKindOf<Variant>() ) {
		wosh::Variant* dataObject = dynamic_cast<wosh::Variant*>(object);
		GuiUtilities::convertQVariant2Variant( dataObject, value );
		emit dataChanged(index, index);
		emit tableCell_changed(index.row(), index.column(), object );
		return true;
	 }
	 return false;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WoshTableView::WoshTableView( QWidget* parent ) : QTableView(parent) {
	this->wTableModel = new WoshTableModel(NULL, this);
	QTableView::setModel(this->wTableModel);
//	this->request = NULL;
//	setDataRequest(_METHOD_List); // default
	setSortingEnabled(true);

//	connect(this->horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortByColumn(int,Qt::SortOrder)));
 }

WoshTableView::~WoshTableView() {
	if ( this->wTableModel != NULL ) delete this->wTableModel;
//	if ( this->request != NULL ) delete this->request;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
void WoshTableView::evalResponse( const Response* response) {
	if ( this->request == NULL ) return;
	if ( response->getMethod() != this->request->getMethod() ) return;

	if ( !response->hasData() ) return;
	if ( !response->getData()->isKindOf<Table>() ) return;

	const wosh::Table* dataTable = response->getData()->as<Table>();
	this->wTableModel->loadTable(dataTable);

	this->horizontalHeader()->setSortIndicator(-1, Qt::AscendingOrder);

	if ( this->resizeMode > 0 ) {
		this->horizontalHeader()->setVisible(dataTable->hasHeaderHorizontal());
		this->resizeColumnsToContents();
	 }
	if ( this->resizeMode > 2 ) {
		this->verticalHeader()->setVisible(dataTable->hasHeaderVertical());
	 }

	if ( this->resizeStretch >= 0 && this->resizeStretch < this->wTableModel->columnCount() )
		this->horizontalHeader()->setResizeMode(this->resizeStretch,QHeaderView::Stretch);

	emit updated();
 }
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WidgetTable::WidgetTable( QWidget *parent )
	: QWidget(parent) {

	this->menuHHeader = NULL;
	this->menuHHeaderTitle = NULL;
	this->menuHHeaderRetrieveCols = NULL;
	this->menuHHeaderDefaultCols = NULL;
	this->menuHHeaderPaging = NULL;
	this->retrievingFields = false;

	this->methodList = _METHOD_List;
	this->methodRetrieve = _METHOD_Retrieve;
	this->methodRetrieveIndex = 0;
	this->methodRetrieveAuto = false;

	this->resizeMode = 3;
	this->resizeStretch = -1;

	this->tableView = new WoshTableView(this);
    this->tableView->setFrameShape(QFrame::Box);
    this->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    this->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    this->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    this->tableView->verticalHeader()->setVisible(false);
//	this->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(this->tableView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(tableItem_ContextMenu( const QPoint&)), Qt::DirectConnection);
	connect(this->tableView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(tableItem_Clicked( const QModelIndex&)), Qt::DirectConnection);
	connect(this->tableView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(tableItem_DoubleClicked( const QModelIndex&)), Qt::DirectConnection);
	this->tableView->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(this->tableView->horizontalHeader(), SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(horizontalHeader_ContextMenu(const QPoint&)) );

	this->wUpdateBar = new WidgetUpdateBar(this);
	connect(this->wUpdateBar, SIGNAL(updateClicked()), this, SLOT(refreshData()));

	this->wPagingControl = new WidgetTablePagingControl(this);
	this->wPagingControl->setVisible(false);
	//connect(this->wPagingControl, SIGNAL(rangeSelected(long,long)),this, SLOT(paging_rangeSelected(long,long)) );
	connect(this->wPagingControl, SIGNAL(rangeSelected(long,long)),this, SLOT(refreshData()) );

	this->vLayout = new QVBoxLayout(this);
	this->vLayout->setContentsMargins(0,0,0,0);
	this->vLayout->setObjectName(QString::fromUtf8("verticalLayout"));
	this->vLayout->addWidget(this->tableView);

	QHBoxLayout* hLayout = new QHBoxLayout(this);
	hLayout->setContentsMargins(0,0,0,0);
	hLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
	hLayout->addWidget(this->wUpdateBar);
	hLayout->addWidget(this->wPagingControl);
	this->vLayout->addLayout(hLayout);

	setLayout(this->vLayout);
 }

WidgetTable::~WidgetTable() {
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
void WidgetTable::paging_rangeSelected( long, long ) {
	refreshData();
 }
*/
void WidgetTable::tableItem_ContextMenu( const QPoint& pos ) {
	QPoint parentPos = this->mapFromParent(pos);
	QModelIndex index = this->tableView->indexAt(pos);
	emit tableContextMenuRequested(parentPos, index);
 }

void WidgetTable::tableItem_Clicked( const QModelIndex& index ) {
	emit tableItemClicked(index);
 }

void WidgetTable::tableItem_DoubleClicked( const QModelIndex& index ) {
	if ( this->methodRetrieveAuto ) {
		Request* retrieveReq = createRequestRetrieve();
		emit postMessage( new Message(retrieveReq) );
		this->wUpdateBar->showMessage( "Retrieving Automation.." );
		return;
	 }
	emit tableItemDoubleClicked(index);
 }

void WidgetTable::horizontalHeader_ContextMenu( const QPoint& pos ) {
	if ( this->menuHHeader == NULL )
		rebuildMenus();
	if ( this->tableView->getTableModel()->getDataTable() != NULL )
		this->menuHHeaderTitle->setText( tr("Table '%1'").arg(this->tableView->getTableModel()->getDataTable()->getTableName().c_str()) );
	else
		this->menuHHeaderTitle->setText( tr("Table Empty [NULL]") );
	QPoint globalPos = this->mapToGlobal(pos);
	QAction* selected = this->menuHHeader->exec( globalPos );
	if ( selected == this->menuHHeaderRetrieveCols ) {
		Request* getFields = new Request(this->methodList);
		Table* args = new Table(2,2);
		args->set<Variant>("fields", 0,0); args->set<Variant>("all", 0,1);
		args->set<Variant>("index-end", 1,0); args->set( new Variant(0), 1,1);
		getFields->setData( args );
		this->retrievingFields = true;
		emit postMessage( new Message(getFields) );
	 }
	else if ( selected == this->menuHHeaderPaging ) {
		this->wPagingControl->setVisible( this->menuHHeaderPaging->isChecked() );
	 }
	else if ( selected == this->menuHHeaderDefaultCols ) {
		this->fieldsAll.free();
	 }

 }

void WidgetTable::rebuildMenus() {
	if ( this->menuHHeader == NULL ) {
		this->menuHHeaderTitle = new QAction(this);
		this->menuHHeaderTitle->setEnabled(false);
		this->menuHHeaderRetrieveCols = new QAction(this);
		this->menuHHeaderRetrieveCols->setText(tr("&Retrieve Fields.."));
		QIcon icon; icon.addPixmap(QPixmap(QString::fromUtf8(":/icons/var/extras/icons/menu.refresh.png")), QIcon::Normal, QIcon::Off);
		this->menuHHeaderRetrieveCols->setIcon(icon);
		this->menuHHeaderDefaultCols = new QAction(this);
		this->menuHHeaderDefaultCols->setText(tr("&Default Fields.."));
		this->menuHHeaderPaging = new QAction(this);
		this->menuHHeaderPaging->setText(tr("&Paging Control"));
		this->menuHHeaderPaging->setCheckable(true);
		this->menuHHeader = new QMenu(this);
	 }
	this->menuHHeader->clear();
	this->menuHHeader->addAction(this->menuHHeaderTitle);
	this->menuHHeader->addSeparator();
	this->menuHHeader->addAction(this->menuHHeaderRetrieveCols);
	this->menuHHeader->addAction(this->menuHHeaderDefaultCols);
	this->menuHHeader->addSeparator();
	// bug, todo: free previous actions
//	QList<QAction*> actions;
	List::ConstIterator it;
	for (it=this->fieldsAll.begin(); it!=this->fieldsAll.end(); ++it ) {
		if ( *it == NULL || !(*it)->isKindOf<Variant>() ) continue;
		const string& name = (*it)->as<Variant>()->toString();
		QAction* colAct = new QAction(this);
		colAct->setText( name.c_str() );
		colAct->setCheckable(true);
		if ( this->tableView->getTableModel()->getDataTable() != NULL ) {
			for(unsigned int col=0; col<this->tableView->getTableModel()->getDataTable()->getCols(); ++col ) {
				ISerializable* object = this->tableView->getTableModel()->getDataTable()->getHeaderHorizontal(col);
				if ( object == NULL || !object->isKindOf<Variant>() ) continue;
				if ( *object->as<Variant>() != *(*it)->as<Variant>() ) continue;
				colAct->setChecked(true);
				break;
			 }
		 }
		this->menuHHeader->addAction(colAct);
	 }
	this->menuHHeader->addSeparator();
	this->menuHHeader->addAction(this->menuHHeaderPaging);

 }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void WidgetTable::refreshData() {
	Request* updateReq = createRequestList();
	emit postMessage( new Message(updateReq) );
	this->wUpdateBar->sayRetrieving();
 }

Request* WidgetTable::createRequestList() {
	Request* updateReq = new Request(this->methodList);
	Table* args = NULL;
	if ( this->wPagingControl->isVisible() ) {
		args = new Table(2+this->fieldsAll.size(),2);
		args->set<Variant>("index-start", 0,0);
		args->set( new Variant(this->wPagingControl->getIndexStart()), 0,1);
		args->set<Variant>("index-end", 1,0);
		args->set( new Variant(this->wPagingControl->getIndexEnd()), 1,1);
	 }
	if ( !this->fieldsAll.isEmpty() ) {
		if ( args == NULL )
			args = new Table(this->fieldsAll.size(),2);
		string fieldsStr = "";
		List::ConstIterator it;
		for (it=this->fieldsAll.begin(); it!=this->fieldsAll.end(); ++it ) {
			if ( *it == NULL || !(*it)->isKindOf<Variant>() ) continue;
			const string& name = (*it)->as<Variant>()->toString();
			fieldsStr += name + ",";
		 }
		args->set<Variant>("fields", 2,0);
		args->set<Variant>(fieldsStr, 2,1);
	 }
	updateReq->setData(args);
	return updateReq;
 }

Request* WidgetTable::createRequestRetrieve( ISerializable* args ) {
	Request* updateReq = new Request(this->methodRetrieve);
	if ( args == NULL ) {
		const ISerializable* keyObj = this->tableView->getItem( this->tableView->currentIndex().row(),this->methodRetrieveIndex );
		if ( keyObj != NULL )
			args = keyObj->clone();
	 }
	updateReq->setData(args);
	return updateReq;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void WidgetTable::evalResponse( const Response* response) {
	if ( response->getMethod() != this->methodList ) return;

	if ( WFAILED(response->getReturnValue()) ) {
		QString errMsg = tr("Response ERROR#%1").arg(response->getReturnValue());
		if ( response->hasData() && response->getData()->isKindOf<Variant>() && response->getData()->as<Variant>() != NULL )
			errMsg += QString(": %1").arg(response->getData()->as<Variant>()->toString().c_str());
		this->wUpdateBar->showError(errMsg);

		if ( response->hasData() && response->getData()->isKindOf<Table>() && response->getData()->as<Table>() != NULL )
			this->tableView->getTableModel()->loadTable(response->getData()->as<Table>());
		else
			this->tableView->getTableModel()->loadTable(NULL);
		emit updated();
	 }

	if ( !response->hasData() ) return;
	if ( !response->getData()->isKindOf<Table>() ) return;
	const wosh::Table* dataTable = response->getData()->as<Table>();

	if ( dataTable != NULL && this->retrievingFields ) { // && dataTable->getRows() == 1 ) {
		this->fieldsAll.free();
		dataTable->getRow(-1, this->fieldsAll, false);
		this->retrievingFields = false;
		rebuildMenus();
		this->wUpdateBar->showMessage( tr("Updated Table header (fields)."), false );
		return;
	 }
	this->tableView->getTableModel()->loadTable(dataTable);

	if ( this->wPagingControl->getPageSize() == 0 )
		this->wPagingControl->setCount( dataTable->getRows() );

	this->tableView->horizontalHeader()->setSortIndicator(-1, Qt::AscendingOrder);

	this->tableView->horizontalHeader()->setSortIndicator(-1, Qt::AscendingOrder);

	if ( this->resizeMode > 0 ) {
		this->tableView->horizontalHeader()->setVisible(dataTable->hasHeaderHorizontal());
		this->tableView->resizeColumnsToContents();
	 }
	if ( this->resizeMode > 2 ) {
		this->tableView->verticalHeader()->setVisible(dataTable->hasHeaderVertical());
	 }

	if ( this->resizeStretch >= 0 && this->resizeStretch < this->tableView->getTableModel()->columnCount() )
		this->tableView->horizontalHeader()->setResizeMode(this->resizeStretch,QHeaderView::Stretch);

	this->wUpdateBar->sayReady();

	emit updated();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WidgetTablePagingControl::WidgetTablePagingControl( QWidget *parent )
	: QWidget(parent) {

	this->count = 0;

	this->spinPage = new QSpinBox(this);
	this->spinPage->setValue(1);
	this->spinPage->setMinimum(1);
	connect(this->spinPage, SIGNAL(valueChanged(int)),this, SLOT(spinPage_valueChanged(int)));

	this->spinPageLen = new QSpinBox(this);
	this->spinPageLen->setValue(0);
	this->spinPageLen->setMinimum(0);
	connect(this->spinPageLen, SIGNAL(valueChanged(int)),this, SLOT(spinPageLen_valueChanged(int)));

	QFrame* line = new QFrame(this);
	line->setFrameShape(QFrame::VLine);
	line->setFrameShadow(QFrame::Sunken);

	QLabel* lblPage = new QLabel(tr("Page"),this);
	lblPage->setEnabled(false);

	this->lblPageCount = new QLabel(this);
	this->lblPageCount->setEnabled(false);
	updatePageCount();

	QHBoxLayout* hLayout = new QHBoxLayout(this);
	hLayout->setContentsMargins(0,0,0,0);
	hLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
	hLayout->addWidget(line);
	hLayout->addWidget( lblPage );
	hLayout->addWidget( this->spinPage );
	hLayout->addWidget( this->lblPageCount );
	hLayout->addWidget( this->spinPageLen );
	setLayout(hLayout);
	resize(80, 25);
 }

void WidgetTablePagingControl::setCount( unsigned int value ) {
	this->count = value;
	this->spinPage->setValue(1);
	this->spinPageLen->setToolTip( tr("%1 total elements").arg(value) );
	this->spinPageLen->setMaximum(value+1);
	updatePageCount();
 }

void WidgetTablePagingControl::updatePageCount() {
	int page_count = this->spinPageLen->value();
	if ( page_count <= 0 ) {
		page_count = 1;
		this->spinPage->setValue(1);
	 }
	else
		page_count = (int)(this->count/this->spinPageLen->value());
	this->spinPage->setMaximum(page_count);
	this->lblPageCount->setText( tr("/ %1, Size:").arg(page_count) );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned int WidgetTablePagingControl::getIndexStart() const {
	return this->spinPageLen->value() * (this->spinPage->value()-1);
 }

unsigned int WidgetTablePagingControl::getIndexEnd() const {
	return this->spinPageLen->value() * (this->spinPage->value());
 }

void WidgetTablePagingControl::spinPage_valueChanged( int ) {
	emit rangeSelected( getIndexStart(), getIndexEnd() );
 }

void WidgetTablePagingControl::spinPageLen_valueChanged( int ) {
	updatePageCount();
	emit rangeSelected( getIndexStart(), getIndexEnd() );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


 }; // namespace gui
}; // namespace wosh
